﻿using Infrastructure.Centers;
using Infrastructure.Filter;
using Infrastructure.Helper;
using Infrastructure.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Minio;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Filters;

namespace Infrastructure.Extensions
{
    public static class ServiceCollectionExtensions
    {
        // 扩展方法，用于添加并配置FileCenter服务
        public static void AddFileCenter(this IServiceCollection services, Action<FileCenterOption> setupAction)
        {
            // 如果传入的配置委托为空，则抛出异常
            if (setupAction == null)
            {
                throw new ArgumentNullException(nameof(setupAction));
            }

            // 创建FileCenter配置实例，并通过委托进行配置
            FileCenterOption optFileCenter = new FileCenterOption();
            setupAction(optFileCenter);

            // 获取FileCenter信息，发送HttpPost请求到配置的URL
            string responseText = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/" +
                optFileCenter.GetMinioUrl, JsonConvert.SerializeObject(new MinioInfoReq
                {
                    AppId = optFileCenter.AppId,
                    AccessKey = optFileCenter.AccessKey
                }));

            // 如果返回的文本非空则处理，否则抛出异常
            if (!string.IsNullOrWhiteSpace(responseText))
            {
                // 反序列化返回结果
                ApiResult apiResult = JsonConvert.DeserializeObject<ApiResult>(responseText);
                // 如果请求未成功，抛出异常
                if (!apiResult.IsSuccess)
                {
                    throw new Exception("查询文件中心失败，请检查文件中心:" + responseText);
                }

                // 反序列化返回的Minio信息
                MinioInfoRes dtoMinioInfoRes = JsonConvert.DeserializeObject<MinioInfoRes>(apiResult.Data.ToString());
                optFileCenter.MinioUrl = dtoMinioInfoRes.MinioUrl;
                optFileCenter.Username = dtoMinioInfoRes.MinioUsername;
                optFileCenter.Password = dtoMinioInfoRes.MinioPassword;

                // 配置Kestrel服务器选项限制最大请求体大小
                services.Configure<KestrelServerOptions>(options =>
                {
                    options.Limits.MaxRequestBodySize = optFileCenter.MaxSizeMBPerFile * 1024 * 1024;
                });

                // 配置表单选项限制最大多部分体长度
                services.Configure<FormOptions>(x =>
                {
                    x.MultipartBodyLengthLimit = optFileCenter.MaxSizeMBPerFile * 1024 * 1024;
                });

                // 注册Minio客户端服务
                services.AddTransient(serviceProvider => new MinioClient()
                    .WithEndpoint(optFileCenter.MinioUrl)
                    .WithCredentials(optFileCenter.Username, optFileCenter.Password)
                    .Build());

                // 注册文件中心服务（单例）
                services.AddSingleton<IFileCenter>(serviceProvider => new FileCenter(
                    serviceProvider.GetRequiredService<MinioClient>(),
                    optFileCenter,
                    serviceProvider.GetRequiredService<IHttpContextAccessor>()
                ));
                return;
            }

            // 请求未返回任何内容，抛出异常
            throw new Exception("查询文件中心失败，请检查文件中心：结果为空");
        }
        public static void AddSwagger(this IServiceCollection services)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            var ApiName = "OPCUA";
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("V1", new OpenApiInfo
                {
                    // {ApiName} 定义成全局变量，方便修改
                    Version = "V1",
                    Title = $"{ApiName} 接口文档——.Net 6.0",
                    Description = $"{ApiName} HTTP API V1",
                });
                c.OrderActionsBy(o => o.RelativePath);

                var xmlPath = Path.Combine(AppContext.BaseDirectory, "OpcUaWebApi.xml");//这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false，这个是controller的注释，记得修改
                // 在header中添加token，传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();
                #region Token绑定到ConfigureServices
                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey
                });
                #endregion
            });

        }
        public static void AddSideCar(this IServiceCollection services, Action<SideCarOption> setupAction)
        {
            if (setupAction == null)
            {
                throw new ArgumentNullException("setupAction");
            }

            services.Configure(setupAction);
        }
        public static void AddControllersWithJsonOptions(this IServiceCollection services)
        {
            services.AddControllers(options =>
            {
                options.SuppressAsyncSuffixInActionNames = false;
                options.Filters.Add<GlobalExceptionsFilter>();
                options.Filters.Add<AppResultFilter>();
            }).AddNewtonsoftJson(options =>
            {
                // JSON 序列化设置...
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            }).ConfigureApiBehaviorOptions(options => options.SuppressModelStateInvalidFilter = true);
        }
    }
}